# relations_controller.pl
use strict;
use warnings;

require '_folders_helper.pl';
require 'relations_helper.pl';

my $FALSE = 0;
my $TRUE  = 1;

my $FOLDER_TYPE = 'relations';

sub controller_relations {
    my ($settings, $params) = @_;

    if (defined $params->{'folder_id'} && $params->{'action'} !~ /^create/) {
        my $is_output = $FALSE;
        my $info = helper_folders_get_info($FOLDER_TYPE, $settings, $params, $is_output);
        if (defined $info && $info->{'mode'} eq 'private') {
            # insist that request is authenticated
            error_unless_authenticated($settings, $params);
        }
    }
}


sub action_relations_list {
    my ($settings, $params) = @_;

    my $full = $params->{'full'};

    #TODO: split system-controlled metadata off from user-controlled value (if latter is big then makes listing slow)
    my $relations_arrayref = helper_list_folders($FOLDER_TYPE, $settings, $params);
    if (performed_render()) {
        return;
    }

    foreach my $folder_info (@$relations_arrayref) {
        # suppress detailed information unless full specified
        if (!$full) {
            delete $folder_info->{'templates'};
            delete $folder_info->{'value'};
        }
    }

    my $text = serialise({'relation' => $relations_arrayref}, {'encode' => 'UTF-8'});
    render({ 'text' => $text });
}


sub action_relations_create {
    my ($settings, $params) = @_;
    
    my $mode = $params->{'mode'};
    my $description = $params->{'description'};
    my $full = $params->{'full'};

    # create info hash which will be serialised to a file in the created folder
    my %info = (
        'type'          => undef,           # set by helper_folders_create
        'id'            => undef,
        'mode'          => $mode,
        'description'   => $description,
        'uri'           => undef,           # set by helper_folders_create
    );
    helper_folders_create($FOLDER_TYPE, $settings, $params, \%info);
    if (performed_render()) {
        return;
    }

    # suppress detailed information unless full specified
    if (!$full) {
        delete $info{'templates'};
        delete $info{'value'};
    }

    # compose response text
    my $text = serialise({'relation' => \%info}, {'encode' => 'UTF-8'});

    render({
        'status'    => '201 Created',
        'headers'   => { 'Location' => $info{'uri'}, },
        'text'      => $text,
    });
}


sub action_relations_destroy {
    my ($settings, $params) = @_;

    my $full = $params->{'full'};

    my $is_output = $TRUE;
    my $folder_info = helper_folders_get_info($FOLDER_TYPE, $settings, $params, $is_output);
    if (performed_render()) {
        return;
    }

    helper_folders_destroy($FOLDER_TYPE, $settings, $params);
    if (performed_render()) {
        return;
    }

    # suppress detailed information unless full specified
    if (!$full) {
        delete $folder_info->{'templates'};
        delete $folder_info->{'value'};
    }

    my $text = serialise({'relation' => $folder_info}, {'encode' => 'UTF-8'});
    render({'text' => $text,});
}


sub action_relations_exists {
    my ($settings, $params) = @_;

    my $exists = helper_folders_exists($FOLDER_TYPE, $settings, $params);
    if (performed_render()) {
        return;
    }

    render({
        'status' => ($exists) ? '200 OK' : '404 Not Found',
        'text' => '',
    });
}


sub action_relations_show {
    my ($settings, $params) = @_;

    my $full = $params->{'full'};

    my $is_output = $TRUE;
    my $folder_info = helper_folders_get_info($FOLDER_TYPE, $settings, $params, $is_output);
    if (performed_render()) {
        return;
    }

    # suppress detailed information unless full specified
    if (!$full) {
        delete $folder_info->{'templates'};
        delete $folder_info->{'value'};
    }

#    my $text = serialise({'relation' => $folder_info}, {'encode' => 'UTF-8'});
    my $text = serialise({'relation' => $folder_info});
    render({ 'text' => $text });
}


sub action_relations_update {
    my ($settings, $params) = @_;
    
    my $is_output = $FALSE;
    my $folder_info = helper_folders_get_info($FOLDER_TYPE, $settings, $params, $is_output);
    if (performed_render()) {
        return;
    }

    my $mode = $params->{'mode'};
    my $description = $params->{'description'};
    my $full = $params->{'full'};

    # update info hash which will be serialised to a file in the relations folder
    my $changed = $FALSE;
    my @properties = (
        ['mode',        'mode',         $mode], 
        ['description', 'description',  $description], 
    );
    foreach (@properties) {
        my ($key, $cgi_key, $value) = @$_;
        if (exists $params->{$cgi_key} && (!defined $folder_info->{$key} || $folder_info->{$key} ne $value)) {
            $folder_info->{$key} = $value;
            $changed = $TRUE;
        }
    }
    if ($changed) {
        helper_folders_put_info($FOLDER_TYPE, $settings, $params, $folder_info);
        if (performed_render()) {
            return;
        }
    }

    # suppress detailed information unless full specified
    if (!$full) {
        delete $folder_info->{'templates'};
        delete $folder_info->{'value'};
    }

    my $text = serialise({'relation' => $folder_info}, {'encode' => 'UTF-8'});
    render({ 'text' => $text });
}


sub action_relations_create_from {
    my ($settings, $params) = @_;

    my $generator = $params->{'generator'};
    my $mode = $params->{'mode'};
    my $description = $params->{'description'};
    my $full = $params->{'full'};

    # because there are multiple route patterns that lead to here, relation_id may be null
    my $relation_ids = $params->{'relation_ids'};
    if (!defined $relation_ids || $relation_ids eq '') {
        # default to relation_id 'list' being our own relations folder id
        $relation_ids = $params->{'folder_id'};
    }

    # build a list of the relation folder ids that are the arguments to this transform
    my @relation_ids_list = ();
    my @ids = split(m|\/|, $relation_ids);
    for my $id (@ids) {
        if ($id eq '' || $id !~ /[a-z][a-z0-9_]*/) {
            render({
                'status' => '404 Not Found',
                'text'   => serialise_error_message("Specified relations folder does not exist:", $id),
            });
            return;
        }
        my $folder_path = helper_folders_path($FOLDER_TYPE, $settings, $params, $id);
        if (performed_render()) {
            return;
        }
        push(@relation_ids_list, $id);
    }

    #FIXME: should be an option with an error reported if overwrite not set to true?
    my $replace = $TRUE;
    if ($replace) {
        # remove any earlier version of the destination folder
        helper_folders_destroy($FOLDER_TYPE, $settings, $params);
        if (performed_render()) {
            return;
        }
    }

    my $templates_hash = helper_parse_json( Encode::decode('Detect', $params->{'templates'}) );
    if (performed_render()) {
        return;
    }

    # create relation info hash which will be serialised to a file in the created folder
    my %info = (
          # generic "thing" parameters
        'type'                  => undef,
        'id'                    => undef,
        'mode'                  => $mode,
        'description'           => $description,
        'uri'                   => undef,
        # id of relation to be copied with transformation
        'relation_ids'          => \@relation_ids_list,
        'generator'             => $generator,
        'templates'            => $templates_hash,
    );
    helper_folders_create($FOLDER_TYPE, $settings, $params, \%info);
    if (performed_render()) {
        return;
    }
    
    # create a manifest describing the transformation
    helper_create_transform_task($FOLDER_TYPE, $settings, $params);
    if (performed_render()) {
        return;
    }

    # perform as much of the transform as can be done in the available time (may be all of it)
    my $complete = helper_transform_next($FOLDER_TYPE, $settings, $params, \%info);
    if (performed_render()) {
        return;
    }

    # suppress return of detailed information unless full specified
    if (!$full) {
        delete $info{'templates'};
        delete $info{'value'};
    }

    # return response appropriate for either queued or completed
    render(
        (defined $complete && $complete == $FALSE)
        ?   {
                'status'    => '202 Accepted',
#                'status'    => '206 Partial Content',
                'text'      => 'ok',
            }
        :   {
                'status'    => '201 Created',
                'headers'   => { 'Location' => $info{'uri'} },
                'text'      => serialise({'relation' => \%info}, {'encode' => 'UTF-8'}),
            }
    );

}


sub action_relations_run {
    my ($settings, $params) = @_;

    my $full = $params->{'full'};

    my $is_output = $FALSE;
    my $folder_info = helper_folders_get_info($FOLDER_TYPE, $settings, $params, $is_output);
    if (performed_render()) {
        return;
    }

    # perform as much of the transform as can be done in the available time (may be all of it)
    my $complete = helper_transform_next($FOLDER_TYPE, $settings, $params, $folder_info);
    if (performed_render()) {
        return;
    }

    # suppress return of detailed information unless full specified
    if (!$full) {
        delete $folder_info->{'templates'};
        delete $folder_info->{'value'};
    }

    # return response appropriate for either queued or completed
    render(
        (defined $complete && $complete == $FALSE)
        ?   {
                'status'    => '202 Accepted',
#                'status'    => '206 Partial Content',
                'text'      => 'ok',
            }
        :   {
                'status'    => '201 Created',
                'text'      => 'ok',
            }
    );
}


1;